"""scipy.spatial子模块提供了一系列用于处理和计算空间数据和几何形状的算法和工具，
在许多领域都有广泛的应用，例如计算机视觉、地理信息系统、机器人学、医学影像分析等。

下面，来具体看看scipy.spatial子模块为我们提供的主要功能分类。

1. 主要功能
scipy.spatial子模块中主要包含的功能有：

类别	说明
空间变换类	目前主要是三维旋转类的函数
最近邻查询类	提供了基于树结构的最近邻搜索算法，如K-d树、球树等，用于在大型空间数据集中快速找到最近邻对象
距离度量类	提供了计算点、线、面等几何形状之间的距离的函数，包括欧几里得距离、曼哈顿距离、切比雪夫距离等。
三角剖分、凸包类	提供了计算二维数据点的凸包的函数，即找到最小的凸多边形来包含所有数据点等
单纯形表示类	提供了三维几何对象的方法，如三维点、向量、矩阵
2. 使用示例
下面演示两个用scipy.spatial子模块中的函数实现的示例。

2.1. 凸包计算示例
给定任意个点，计算凸包就是计算包含给定点集中所有点的最小凸对象。"""

from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial.transform import Rotation
import matplotlib
import matplot_config

matplot_config.init_config()

# 随机生成100个点
points = np.random.rand(100, 2)
# 计算这些点的凸包
hull = ConvexHull(points)

# 绘制一个随机点
plt.scatter(points[:, 0], points[:, 1], marker='o')
# 将位于凸包上的点用红色线连接起来
for simplex in hull.simplices:
    plt.plot(points[simplex, 0], points[simplex, 1], 'r-')

plt.show()
"""image.png

2.2. 三维旋转示例
使用scipy.spatial子模块来做三维旋转非常简单，它提了多种旋转三维物体的方法，
可以通过欧拉角，轴角，旋转向量，四元组，以及旋转矩阵。

使用方式类似，下面演示的是用欧拉角来旋转一个三维球体。
首先绘制一个球体：
"""
fig = plt.figure()
ax = fig.add_subplot(projection='3d')

# 球面点的数据
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))

ax.plot_surface(x, y, z, cmap=plt.cm.rainbow)

ax.set_aspect('equal')
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")

plt.show()
# image.png
#
# 然后用 scipy.spatial 中的方法分别沿X轴旋转45度，沿Y轴旋转90度。


# 沿着 "axis" 轴旋转 "degree" 角度
def rotate(axis, degree):
    r = Rotation.from_euler(axis, degree, degrees=True)
    v = np.dstack((x, y, z))
    v = r.apply(v.reshape(-1, 3))
    v = v.reshape((*z.shape, 3))
    return v


fig, ax = plt.subplots(1, 2, subplot_kw={"projection": "3d"})

v = rotate('x', 45)
ax[0].plot_surface(v[:, :, 0], v[:, :, 1], v[:, :, 2],
                   cmap=plt.cm.rainbow)
ax[0].set_aspect('equal')
ax[0].set_title("沿X轴旋转45度")

v = rotate('y', 90)
ax[1].plot_surface(v[:, :, 0], v[:, :, 1], v[:, :, 2],
                   cmap=plt.cm.rainbow)
ax[1].set_aspect('equal')
ax[1].set_title("沿Y轴旋转90度")

plt.show()
"""image.png

3. 总结
总之，scipy.spatial子模块的重点应用领域有：
距离计算问题，通过计算点、线、面等几何形状之间的距离，可以用于图像配准、碰撞检测、空间聚类等应用；
还有空间插值方法，可以将离散的空间数据转换为连续的函数，用于图像处理、数值分析等领域；
凸包算法，用于图像处理中的对象识别、区域提取等任务；
几何形状操作方法，可以对二维或三维的几何对象进行合并、相交、相减等操作，用于计算机图形学、机器人路径规划等应用；
最近邻搜索算法，在大型空间数据集中快速找到最近邻对象，用于推荐系统、空间索引等应用；

此外，该子模块还提供了排列组合、阶乘和伽马函数等数学计算操作。"""